package com.directions.android.screens;

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.widget.DrawerLayout;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.TextView;
import android.widget.Toast;

import com.directions.android.BundleUtils;
import com.directions.android.DialogUtils;
import com.directions.android.DialogUtils.TextInputListener;
import com.directions.android.R;
import com.directions.android.listview.EnhancedListView;
import com.directions.android.screens.MenuFragment.OnShowMapListener;
import com.directions.android.storage.Location;
import com.directions.android.storage.sqlite.LocationSQLiteHelper;
import com.google.android.gms.internal.de;

public class MarkersFragment extends Fragment {

	private EnhancedListAdapter mAdapter;
	private EnhancedListView mListView;
	private DrawerLayout mDrawerLayout;

	private OnShowMapListener mCallback;
	private View rootView;

	public static Fragment getInstance() {
		Fragment markersFragment = new MarkersFragment();
		return markersFragment;
	}

	@Override
	public void onAttach(Activity activity) {
		super.onAttach(activity);

		// This makes sure that the container activity has implemented
		// the callback interface. If not, it throws an exception
		try {
			mCallback = (OnShowMapListener) activity;
		} catch (ClassCastException e) {
			throw new ClassCastException(activity.toString()
					+ " must implement OnHeadlineSelectedListener");
		}
	}

	public MarkersFragment() {
	}

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		super.onCreateView(inflater, container, savedInstanceState);
		rootView = inflater
				.inflate(R.layout.enhanced_markers, container, false);
		mDrawerLayout = (DrawerLayout) rootView.findViewById(R.id.drawer);
		mDrawerLayout.setDrawerListener(new DrawerLayout.DrawerListener() {
			@Override
			public void onDrawerSlide(View view, float v) {
			}

			@Override
			public void onDrawerOpened(View view) {
				mListView.discardUndo();
				getActivity().supportInvalidateOptionsMenu();
			}

			@Override
			public void onDrawerClosed(View view) {
				getActivity().supportInvalidateOptionsMenu();
				applySettings();
			}

			@Override
			public void onDrawerStateChanged(int i) {
			}

		});

		mListView = (EnhancedListView) rootView.findViewById(R.id.list);

		mAdapter = new EnhancedListAdapter();
		mAdapter.resetItems();

		mListView.setAdapter(mAdapter);

		// Set the callback that handles dismisses.
		mListView.setDismissCallback(new EnhancedListView.OnDismissCallback() {
			/**
			 * This method will be called when the user swiped a way or deleted
			 * it via
			 * {@link de.timroes.android.listview.EnhancedListView#delete(int)}.
			 * 
			 * @param listView
			 *            The {@link EnhancedListView} the item has been deleted
			 *            from.
			 * @param position
			 *            The position of the item to delete from your adapter.
			 * @return An
			 *         {@link de.timroes.android.listview.EnhancedListView.Undoable}
			 *         , if you want to give the user the possibility to undo
			 *         the deletion.
			 */
			@Override
			public EnhancedListView.Undoable onDismiss(
					EnhancedListView listView, final int position) {

				final Location item = (Location) mAdapter.getItem(position);
				mAdapter.remove(position);
				return new EnhancedListView.Undoable() {
					@Override
					public void undo() {
						mAdapter.insert(position, item);
					}
				};
			}
		});

		// Show toast message on click and long click on list items.
		mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
			@Override
			public void onItemClick(AdapterView<?> parent, View view,
					int position, long id) {
				Toast.makeText(getActivity(),
						"Clicked on item " + mAdapter.getItem(position),
						Toast.LENGTH_SHORT).show();
				Location marker = (Location) mAdapter.getItem(position);

				Bundle mapInfo = new Bundle();
				mapInfo.putDouble(BundleUtils.ORIG_LAT, marker.getLatitude());
				mapInfo.putDouble(BundleUtils.ORIG_LONG, marker.getLongitude());
				mapInfo.putString(BundleUtils.MARKER_TITLE, marker.getTitle());
				mapInfo.putInt(BundleUtils.MARKER_ID, marker.getId());

				mCallback.onShowMap(mapInfo);
			}
		});
		mListView
				.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
					@Override
					public boolean onItemLongClick(AdapterView<?> parent,
							View view, int position, long id) {

						final Location marker = (Location) mAdapter
								.getItem(position);

						DialogUtils.getTextInput(getActivity(), getActivity()
								.getString(R.string.location_title),
								getString(R.string.location_title), marker
										.getTitle(), new TextInputListener() {

									@Override
									public void input(String msg) {
										if (msg == null || msg.isEmpty())
											return;
										marker.setTitle(msg);
										mAdapter.update(marker);
									}

									@Override
									public void canceled() {

									}
								});

						return true;
					}
				});

		mListView.setSwipingLayout(R.id.swiping_layout);

		applySettings();

		return rootView;
	}

	@Override
	public void onResume() {
		super.onResume();
	}

	/**
	 * Applies the settings the user has made to the list view.
	 */
	private void applySettings() {

		// Set the UndoStyle, the user selected.
		EnhancedListView.UndoStyle style = EnhancedListView.UndoStyle.MULTILEVEL_POPUP;
		// EnhancedListView.UndoStyle style =
		// EnhancedListView.UndoStyle.SINGLE_POPUP;
		// EnhancedListView.UndoStyle style =
		// EnhancedListView.UndoStyle.COLLAPSED_POPUP;

		mListView.setUndoStyle(style);

		// Enable or disable Swipe to Dismiss
		mListView.enableSwipeToDismiss();

		// Set the swipe direction
		EnhancedListView.SwipeDirection direction = EnhancedListView.SwipeDirection.BOTH;
		// EnhancedListView.SwipeDirection direction=
		// EnhancedListView.SwipeDirection.START;
		// EnhancedListView.SwipeDirection direction=
		// EnhancedListView.SwipeDirection.END;

		mListView.setSwipeDirection(direction);

		// Enable or disable swiping layout feature
		mListView.setSwipingLayout(R.id.swiping_layout);
		// mListView.setSwipingLayout(0);

	}

	@Override
	public void onStop() {
		if (mListView != null) {
			mListView.discardUndo();
		}
		super.onStop();
	}

	@Override
	public void onPrepareOptionsMenu(Menu menu) {
		boolean drawer = mDrawerLayout.isDrawerVisible(Gravity.RIGHT);

		menu.findItem(R.id.action_settings).setVisible(!drawer);
		menu.findItem(R.id.action_done).setVisible(drawer);
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case R.id.action_settings:
			mDrawerLayout.openDrawer(Gravity.RIGHT);
			return true;
		case R.id.action_done:
			mDrawerLayout.closeDrawers();
			return true;
		}
		return super.onOptionsItemSelected(item);
	}

	private class EnhancedListAdapter extends BaseAdapter {

		private List<Location> mItems = new ArrayList<Location>();
		private LocationSQLiteHelper sqlite;

		void resetItems() {
			mItems.clear();
			setUpSQLiteIfNeeded();
			getList(mItems);
			notifyDataSetChanged();
		}

		public void remove(int position) {
			Location removed = mItems.remove(position);
			setUpSQLiteIfNeeded();
			sqlite.delete(removed);
			notifyDataSetChanged();
		}

		public void insert(int position, Location item) {
			mItems.add(position, item);
			setUpSQLiteIfNeeded();
			sqlite.insert(item);
			notifyDataSetChanged();
		}

		public void update(Location location) {
			setUpSQLiteIfNeeded();
			sqlite.updateRow(location);
			notifyDataSetChanged();
		}

		/**
		 * How many items are in the data set represented by this Adapter.
		 * 
		 * @return Count of items.
		 */
		@Override
		public int getCount() {
			return mItems.size();
		}

		/**
		 * Get the data item associated with the specified position in the data
		 * set.
		 * 
		 * @param position
		 *            Position of the item whose data we want within the
		 *            adapter's data set.
		 * @return The data at the specified position.
		 */
		@Override
		public Object getItem(int position) {
			return mItems.get(position);
		}

		/**
		 * Get the row id associated with the specified position in the list.
		 * 
		 * @param position
		 *            The position of the item within the adapter's data set
		 *            whose row id we want.
		 * @return The id of the item at the specified position.
		 */
		@Override
		public long getItemId(int position) {
			return position;
		}

		/**
		 * Get a View that displays the data at the specified position in the
		 * data set. You can either create a View manually or inflate it from an
		 * XML layout file. When the View is inflated, the parent View
		 * (GridView, ListView...) will apply default layout parameters unless
		 * you use
		 * {@link android.view.LayoutInflater#inflate(int, android.view.ViewGroup, boolean)}
		 * to specify a root view and to prevent attachment to the root.
		 * 
		 * @param position
		 *            The position of the item within the adapter's data set of
		 *            the item whose view we want.
		 * @param convertView
		 *            The old view to reuse, if possible. Note: You should check
		 *            that this view is non-null and of an appropriate type
		 *            before using. If it is not possible to convert this view
		 *            to display the correct data, this method can create a new
		 *            view. Heterogeneous lists can specify their number of view
		 *            types, so that this View is always of the right type (see
		 *            {@link #getViewTypeCount()} and
		 *            {@link #getItemViewType(int)}).
		 * @param parent
		 *            The parent that this view will eventually be attached to
		 * @return A View corresponding to the data at the specified position.
		 */
		@Override
		public View getView(int position, View convertView, ViewGroup parent) {

			ViewHolder holder;
			if (convertView == null) {
				convertView = getActivity().getLayoutInflater().inflate(
						R.layout.list_item, parent, false);
				// Clicking the delete icon, will read the position of the item
				// stored in
				// the tag and delete it from the list. So we don't need to
				// generate a new
				// onClickListener every time the content of this view changes.
				final View origView = convertView;
				convertView.findViewById(R.id.action_delete)
						.setOnClickListener(new View.OnClickListener() {
							@Override
							public void onClick(View view) {
								mListView.delete(((ViewHolder) origView
										.getTag()).position);
							}
						});

				holder = new ViewHolder();
				assert convertView != null;
				holder.mTextView = (TextView) convertView
						.findViewById(R.id.text);

				convertView.setTag(holder);
			} else {
				holder = (ViewHolder) convertView.getTag();
			}

			holder.position = position;
			holder.mTextView.setText(mItems.get(position).getTitle());

			return convertView;
		}

		private void setUpSQLiteIfNeeded() {
			if (sqlite == null) {
				sqlite = new LocationSQLiteHelper(getActivity());
			}
		}

		private void getList(List<Location> titles) {
			try {
				titles = sqlite.getList(getActivity(), titles);
			} catch (Exception e) {
				Toast.makeText(getActivity().getApplicationContext(),
						"Couldn't retrieve the locations.", Toast.LENGTH_SHORT)
						.show();
			}
		}

		private class ViewHolder {
			TextView mTextView;
			int position;
		}
	}
}
